<?php

namespace app\utils\VueAdmin;


use App\Master\Framework\Extend\Core;
use App\Master\Framework\Extend\Module as FrameworkModule;
use App\Services\AliCloud\OssService;
use App\Services\Tencent\CosService;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
use zgldh\QiniuStorage\QiniuStorage;

class Uploads
{

    /*文件类型*/
    protected static $_fileType = 'image';

    /*mp4,wmv,rm,rmvb,m4v,mkv*/
    public static $_fileExt      = [
        'image' => 'jpg,png,bmp,jpeg,gif',
        'video' => 'wmv,asf,asx,rm,rmvb,mp4,3gp,mov,m4v,avi,dat,mkv,flv,vob',
        'audio' => 'mp3,wma,avi,mpg,wav,flac,ape,alac',
        'file'  => 'doc,docx,xls,xlsx,xlsm,xlt,xltx,xltm,csv',
        'media' => 'mp3,wma,avi,rm,rmvb,flv,mpg,mov,mk,mp4,3gp',
        'flash' => 'swf,rm,mov,gif,png,mpeg'
    ];
    public static $_fileTypeExt  = [
        '1' => 'jpg,png,bmp,jpeg,gif',
        '2' => 'mp3,wma,avi,rm,rmvb,flv,mpg,mov,mk,mp4',
        '3' => 'doc,docx,xls,xlsx,xlsm,xlt,xltx,xltm,csv',
    ];
    public static $_fileTypeMaps = ['1' => 'image', '2' => 'media', '3' => 'file'];

    public static $_fileOptions = [
        'file_size'   => '',
        'file_ext'    => 'jpg',
        'file_name'   => '',
        'original'    => '',
        'format_size' => 0,
        'disk'        => '',
        'url'         => '',
        'path'        => '',
        'name'        => ''
    ];

    /*文件对象*/
    protected static $_files;

    /*错误信息*/
    protected static $_message = ['code' => 0, 'msg' => '', 'data' => []];

    /*上传参数*/
    public static $_options = [
        'path'   => 'uploads/',
        'size'   => 50,
        'dir'    => '',
        'suffix' => '',
    ];

    /*静态资源*/
    private static $instance = null;

    private function __construct($type = 'image', $options = [])
    {
        self::$_fileType = $type;

        self::$_options = array_merge(self::$_options, $options);
    }

    public static function getInstance($type = 'image', $options = [])
    {
        if (!isset(self::$instance)) {
            self::$instance = new self($type, $options);
        }
        return self::$instance;
    }

    /**
     * Get the registered name of the component.
     *
     * @return string
     */
    protected static function getFacadeAccessor()
    {
        return 'Upload';
    }

    /**
     * 图片快速上传
     * @param string $key 文件对象key $_FILES[$key]
     * @return self
     */
    public function init($key = 'file')
    {
        $files = Request::capture()->allFiles();
        if (empty($files) || !isset($files[$key]) || empty($files[$key])) {
            return self::setMessage(1010, '请上传文件！');
        }
        if (!Request::capture()->file($key)->isValid()) {
            return self::setMessage(1012, '请上传文件！');
        }
        if (isset(self::$_options['type']) && isset(self::$_fileTypeMaps[self::$_options['type']])) {
            self::$_fileType = self::$_fileTypeMaps[self::$_options['type']];
        }

        if (!isset(self::$_fileExt[self::$_fileType])) {
            return $this->$this->setMessage(1013, '不支持的文件类型！');
        }

        self::$_files                    = $files[$key];
        $ext                             = self::$_files->getClientOriginalExtension();
        self::$_fileOptions['file_size'] = self::$_files->getSize();
        self::$_fileOptions['file_ext']  = $ext ? strtolower($ext) : 'jpg';
        self::$_fileOptions['file_name'] = self::$_fileOptions['original'] = self::$_files->getClientOriginalName();
        if (!self::_checkFileSize()) {
            return self::setMessage(1013, '请上传' . self::$_options['size'] . 'M以内的文件！');
        }
        if (!self::_checkExt()) {
            return self::setMessage(1014, '请上传' . strtolower(self::$_fileExt[self::$_fileType]) . '类型的文件！');
        }
        self::$_fileOptions['name'] = Core::createUnique() . "." . self::$_fileOptions['file_ext'];
        self::$_fileOptions['path'] = self::$_options['path'] . self::$_fileType . '/' . date('Ymd') . '/';
        if (!is_dir(public_path(self::$_fileOptions['path']))) {
            if (!mkdir(public_path(self::$_fileOptions['path']), 0777, true)) {
                return self::setMessage(1013, '文件上传失败，请重试！');
            }
        }
        $store  = FrameworkModule::_SetupModule('FileStore');
        $driver = isset($store['driver']) ? $store['driver'] : 'local';
        switch ($driver) {
            case 'qiniu':
                $config = $store['qiniu'] ?? [];
                $res    = self::_QiNiu($config);
                break;
            case 'oss':
                $config = $store['oss'] ?? [];
                $res    = self::_AliOss($config);
                break;
            default:
                $config = $store['config'] ?? [];
                $res    = self::_Local($config);
        }

        if (!$res || !self::$_fileOptions['url']) {
            return self::setMessage(1015, '文件上传失败！');
        }
        unset($files, $store);
        return self::setMessage(200, '文件上传成功！');
    }

    private static function _QiNiu($config)
    {
        if (!isset($config['access_key']) || empty($config['access_key'])) {
            return false;
        }
        if (!isset($config['default']) || empty($config['default'])) {
            return false;
        }
        self::$_fileOptions['path'] = self::$_fileOptions['path'] . self::$_fileOptions['name'];
        config(['filesystems.disks.qiniu' => [
            'driver'                 => 'qiniu',
            'domains'                => [
                'default' => $config['default'], //你的七牛域名
                'https'   => $config['https'],  //你的HTTPS域名
                'custom'  => $config['default'], //Useless 没啥用，请直接使用上面的 default 项
            ],
            'domain'                 => $config['default'],
            'access_key'             => $config['access_key'],  //AccessKey
            'secret_key'             => $config['secret_key'],  //SecretKey
            'bucket'                 => $config['bucket'],  //Bucket名字
            'notify_url'             => '',  //持久化处理回调地址
            'access'                 => 'public',  //空间访问控制 public 或 private
            'hotlink_prevention_key' => null, // CDN 时间戳防盗链的 key。 设置为 null 则不启用本功能。
        ]]);

        if (self::$_fileOptions['file_size'] > 10485760) {
            if (!Storage::disk('qiniu')->put(self::$_fileOptions['path'], fopen(self::$_files->getRealPath(), 'r+'))) {
                return false;
            }
        } else {
            if (!Storage::disk('qiniu')->put(self::$_fileOptions['path'], file_get_contents(self::$_files->getRealPath()))) {
                return false;
            }
        }
        $domain                     = $config['https'] ? $config['https'] : $config['default'];
        self::$_fileOptions['disk'] = $domain;
        self::$_fileOptions['url']  = $domain . '/' . self::$_fileOptions['path'];
        self::$_fileOptions['size'] = round((self::$_fileOptions['file_size'] / 1024), 2) . 'kB';
        return true;
    }

    private static function _AliOss($config)
    {
        if (!isset($config['access_id']) || empty($config['access_id'])) {
            return false;
        }
        if (!isset($config['access_key']) || empty($config['access_key'])) {
            return false;
        }
        if (!isset($config['bucket']) || empty($config['bucket'])) {
            return false;
        }
        if (!isset($config['endpoint']) || empty($config['endpoint'])) {
            return false;
        }
        self::$_fileOptions['path'] = self::$_fileOptions['path'] . self::$_fileOptions['name'];
        $endpoint                   = "oss-{$config['endpoint']}.aliyuncs.com";
        $is_custom                  = (boolean)($config['is_custom'] ?? false);
        $ssl                        = (boolean)($config['ssl'] ?? false);
        config(['filesystems.disks.oss' => [
            'driver'            => "oss",
            'access_key_id'     => $config['access_id'],                               // 必填, 阿里云的AccessKeyId
            'access_key_secret' => $config['access_key'],                              // 必填, 阿里云的AccessKeySecret
            'bucket'            => $config['bucket'],                                  // 必填, 对象存储的Bucket, 示例: my-bucket
            'endpoint'          => $is_custom ? $config['custom_domain'] : $endpoint,  // 必填, 对象存储的Endpoint, 示例: oss-cn-shanghai.aliyuncs.com
            'domain'            => $is_custom ? $config['custom_domain'] : '',         // 选填, 绑定域名,填写即启用 示例: oss.my-domain.com
            'is_cname'          => (boolean)($config['is_custom'] ?? false),           // 选填, 若Endpoint为自定义域名，此项要为true，见：https://github.com/aliyun/aliyun-oss-php-sdk/blob/572d0f8e099e8630ae7139ed3fdedb926c7a760f/src/OSS/OssClient.php#L113C1-L122C78
            'use_ssl'           => (boolean)($config['ssl'] ?? false),                 // 选填, 是否使用HTTPS
            'reverse_proxy'     => false,                                              // 选填, 域名是否使用NGINX代理绑定
            'throw'             => true,                                               // 选填,
            'options'           => [],                                                 // 选填, 添加全局配置参数, 示例: [\OSS\OssClient::OSS_CHECK_MD5 => false]
            'macros'            => []
        ]]);
        if (!Storage::disk('oss')->put(self::$_fileOptions['path'], file_get_contents(self::$_files->getRealPath()))) {
            return false;
        }
        $domain                     = ($ssl ? 'https://' : 'http://') . ($is_custom ? $config['custom_domain'] : "{$config['bucket']}.$endpoint");
        self::$_fileOptions['disk'] = $domain;
        self::$_fileOptions['url']  = $domain . '/' . self::$_fileOptions['path'];
        self::$_fileOptions['size'] = round((self::$_fileOptions['file_size'] / 1024), 2) . 'kB';
        return true;
    }

    private static function _Local($config)
    {
        /*移动文件*/
        self::$_files->move(self::$_fileOptions['path'], self::$_fileOptions['name']);
        $domain                          = config('framework.bases.host.image') ? config('framework.bases.host.image') : Core::hosts();
        self::$_fileOptions['disk']      = $domain;
        self::$_fileOptions['file_path'] = self::$_fileOptions['path'] . self::$_fileOptions['name'];
        self::$_fileOptions['url']       = '/' . self::$_fileOptions['path'] . self::$_fileOptions['name'];
        self::$_fileOptions['size']      = round((self::$_fileOptions['file_size'] / 1024), 2) . 'kB';
        return true;
    }

    private static function setMessage($code, $msg, $data = [])
    {
        self::$_message = ['code' => $code, 'msg' => $msg, 'data' => $data ? $data : self::$_fileOptions];
        return self::getInstance();
    }

    public function getMessage()
    {
        return self::$_message;
    }

    private function _checkFileSize()
    {
        /*验证文件大小*/
        if (self::$_options['size'] <= 0) {
            return true;
        }
        if (self::$_fileOptions['file_size'] > (1024 * 1024 * self::$_options['size'])) {
            return false;
        }
        return true;
    }

    protected function _checkExt()
    {
        if (self::$_options['suffix']) {
            self::$_fileExt[self::$_fileType] = self::$_options['suffix'];
        }
        if (!isset(self::$_fileExt[self::$_fileType])) {
            return true;
        }

        if (!$ext_items = explode(',', strtolower(self::$_fileExt[self::$_fileType]))) {
            return true;
        }
        if (!in_array(self::$_fileOptions['file_ext'], $ext_items)) {
            return false;
        }
        return true;
    }

    public function token()
    {
        $store  = config('vue.upload');
        $driver = isset($store['driver']) ? $store['driver'] : 'local';
        switch ($driver) {
            case 'qiniu':
                if (!$config = $store['qiniu'] ?? []) {
                    return self::setMessage(1001, '上传参数配置错误！');
                }
                config(['filesystems.disks.qiniu' => [
                    'driver'                 => 'qiniu',
                    'domains'                => [
                        'default' => $config['default'], //你的七牛域名
                        'https'   => $config['https'],  //你的HTTPS域名
                        'custom'  => $config['default'], //Useless 没啥用，请直接使用上面的 default 项
                    ],
                    'domain'                 => $config['default'],
                    'access_key'             => $config['access_key'],  //AccessKey
                    'secret_key'             => $config['secret_key'],  //SecretKey
                    'bucket'                 => $config['bucket'],  //Bucket名字
                    'notify_url'             => '',  //持久化处理回调地址
                    'access'                 => 'public',  //空间访问控制 public 或 private
                    'hotlink_prevention_key' => null, // CDN 时间戳防盗链的 key。 设置为 null 则不启用本功能。
                ]]);
                $token = QiniuStorage::disk('qiniu')->uploadToken();
                return self::setMessage(200, 'success！', [
                    'token'     => $token,
                    'domain'    => $config['https'],
                    'action'    => $config['default'],
                    'driver'    => 'qiniu',
                    'key'       => '',
                    'save_path' => $this->getSavePath()
                ]);
            case 'oss':
                $config = $store['oss'] ?? [];
                config(['filesystems.disks.oss' => [
                    'driver'            => "oss",
                    'access_key_id'     => $config['access_id'],   // 必填, 阿里云的AccessKeyId
                    'access_key_secret' => $config['access_key'],   // 必填, 阿里云的AccessKeySecret
                    'bucket'            => $config['bucket'],   // 必填, 对象存储的Bucket, 示例: my-bucket
                    'endpoint'          => $config['endpoint'],   // 必填, 对象存储的Endpoint, 示例: oss-cn-shanghai.aliyuncs.com
                    'internal'          => null, // 选填, 内网上传地址,填写即启用 示例: oss-cn-shanghai-internal.aliyuncs.com
                    'domain'            => null, // 选填, 绑定域名,填写即启用 示例: oss.my-domain.com
                    'is_cname'          => false,// 选填, 若Endpoint为自定义域名，此项要为true，见：https://github.com/aliyun/aliyun-oss-php-sdk/blob/572d0f8e099e8630ae7139ed3fdedb926c7a760f/src/OSS/OssClient.php#L113C1-L122C78
                    'prefix'            => "",   // 选填, 统一存储地址前缀
                    'use_ssl'           => (boolean)$config['ssl'],// 选填, 是否使用HTTPS
                    'reverse_proxy'     => false,// 选填, 域名是否使用NGINX代理绑定
                    'throw'             => false,// 选填, 是否抛出引起错误的异常,默认出现错误时,不抛出异常仅返回false
                    'options'           => [],   // 选填, 添加全局配置参数, 示例: [\OSS\OssClient::OSS_CHECK_MD5 => false]
                    'macros'            => []
                ]]);
                $oss = new OssService();
//                list($is_true, $data) = $oss->getStsToken(self::$_options['path']);
                list($is_true, $data) = $oss->getToken(self::$_options['path']);

                if ($is_true !== true) {
                    return self::setMessage(201, $data);
                }
                return self::setMessage(200, 'success！', array_merge($data, [
                    'driver'    => 'oss',
                    'save_path' => $this->getSavePath()
                ]));
            case 'cos':
                $config = $store['cos'] ?? [];
                config(['filesystems.disks.cos' => [
                    'driver'     => 'cos',
                    'app_id'     => $config['app_id'],
                    'secret_id'  => $config['secret_id'],
                    'secret_key' => $config['secret_key'],
                    'bucket'     => $config['bucket'],
                    'region'     => $config['region'],
                    'cos_url'    => $config['cos_url'],
                    'ssl'        => (boolean)$config['ssl'], // true to use 'https://' and false to use 'http://'. default is false,
                ]]);
                $oss = new CosService();
                list($is_true, $data) = $oss->getSignedUrl(self::$_options['path']);

                if (!$is_true) {
                    return self::setMessage(201, $data);
                }
                return self::setMessage(200, 'success！', array_merge($data, [
                    'driver'    => 'cos',
                    'save_path' => $this->getSavePath()
                ]));
            default:
                return self::setMessage(200, 'success！', [
                    'token'  => '',
                    'domain' => '',
                    'action' => '/vue/pictureUploads',
                    'driver' => $driver,
                ]);
        }
    }

    public function getFileKey()
    {
        $file_name = \request()->input('file_name', '');
        $type      = intval(\request()->input('type', 1));
        if (empty($file_name)) {
            self::setMessage(201, '获取失败！');
        }
        $file     = explode('.', $file_name);
        $suffix   = '.' . end($file);
        $savePath = self::$_options['path'] . (self::$_fileTypeMaps[$type]) . '/' . date('Ymd') . '/';
        return self::setMessage(200, 'success！', [
            'key' => $savePath . Core::createUnique() . $suffix
        ]);
    }

    // 获取存储目录
    public function getSavePath()
    {
        return [
            'path'         => self::$_options['path'],
            'fileTypeMaps' => self::$_fileTypeMaps,
            'date'         => date('Ymd')
        ];
    }

    public static function createFileName($type, $suffix = '.jpg')
    {
        $savePath = '/' . self::$_options['path'] . (self::$_fileTypeMaps[$type]) . '/' . date('Ymd') . '/';

        if (!is_dir('.' . $savePath)) {
            mkdir('.' . $savePath, 0777, true);//创建文件上传目录
        }

        return $savePath . Core::createUnique() . $suffix;
    }

    public static function disksQiNiu()
    {
        $store = FrameworkModule::_SetupModule('FileStore');
        if ((isset($store['driver']) ? $store['driver'] : 'local') != 'qiniu') {
            return false;
        }
        if (!$config = $store['qiniu'] ?? []) {
            return false;
        }
        config(['filesystems.disks.qiniu' => [
            'driver'                 => 'qiniu',
            'domains'                => [
                'default' => $config['default'], //你的七牛域名
                'https'   => $config['https'],  //你的HTTPS域名
                'custom'  => $config['https'], //Useless 没啥用，请直接使用上面的 default 项
            ],
            'domain'                 => $config['https'],
            'access_key'             => $config['access_key'],  //AccessKey
            'secret_key'             => $config['secret_key'],  //SecretKey
            'bucket'                 => $config['bucket'],  //Bucket名字
            'notify_url'             => '',  //持久化处理回调地址
            'access'                 => 'public',  //空间访问控制 public 或 private
            'hotlink_prevention_key' => null, // CDN 时间戳防盗链的 key。 设置为 null 则不启用本功能。
        ]]);
        return QiniuStorage::disk('qiniu');
    }

    /**
     * 远程下载文件
     * @param $file_url
     * @param $save_to
     */
    public static function downloadRemoteWithCurl($file_url, $save_to)
    {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_POST, 0);
        curl_setopt($ch, CURLOPT_URL, $file_url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        $file_content = curl_exec($ch);
        curl_close($ch);

        $downloaded_file = fopen($save_to, 'w');
        fwrite($downloaded_file, $file_content);
        fclose($downloaded_file);
    }
}
